package com.raptor.trustworthy.task.service.Impl;


import com.raptor.trustworthy.task.dao.ScheduleJobDao;
import com.raptor.trustworthy.task.model.ScheduleJob;
import com.raptor.trustworthy.task.service.ScheduleJobService;
import com.raptor.trustworthy.task.service.ScheduleTaskService;
import com.raptor.trustworthy.task.task.JobExchange;
import com.raptor.trustworthycore.util.DateUtil;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.TriggerUtils;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * 定时任务服务实现类
 *
 * @Author renhuan
 * @Date 2021-03-27 15:34
 **/
@Service("scheduleJobService")
public class ScheduleJobServiceImpl implements ScheduleJobService {

  private final static Logger log = LoggerFactory.getLogger(ScheduleJobServiceImpl.class);


  @Autowired
  private SchedulerFactoryBean schedulerFactoryBean;

  @Autowired
  private ScheduleJobDao scheduleJobDao;

  @Autowired
  private Scheduler scheduler;


  @Override
  public Map<String, Object> getScheduleJob() {
    Map<String, Object> res = new HashMap<>();
    List<ScheduleJob> scheduleJobList = new ArrayList<>();
    try {
      scheduleJobList = scheduleJobDao.getScheduleJobList();
      res.put("scheduleJobList", scheduleJobList);
//      res.put("page",page);
    } catch (Exception e) {
      log.error("getScheduleJobList exception: " + e);
    }
    return res;
  }


  /**
   * 批量启用定时任务，暂不支持
   */
//  @Override
//  public ResultBean<List<Map<String, String>>> startJobs(Long[] jobIds) {
//    try {
//      //批量启动定时任务前，查询所有要启动的定时任务
//      List<ScheduleJob> jobList = this.scheduleJobDao.getJobs(jobIds);
//      for (int i = jobList.size() - 1; i >= 0; i--) {
//        ScheduleJob job = jobList.get(i);
//        //如果已经是启动状态，则不管，也不需要更新状态
//        if ("1".equals(job.getState())) {
//          jobList.remove(i);
//          continue;
//        } else {
//          //如果是禁用状态，更新状态，并启动任务
//          job.setState("1");
//          if ("1".equals(env.getProperty("dsrwbz"))) {
//            createJob(job);
//          }
//        }
//      }
//      //如果有要更新的数据，则执行更新
//      if (!jobList.isEmpty()) {
//        this.scheduleJobDao.save(jobList);
//      }
//    } catch (Exception e) {
//      e.printStackTrace();
//      return new ResultBean<List<Map<String, String>>>(-1, "启动失败！");
//    }
//    return new ResultBean<List<Map<String, String>>>(0, "启动成功！");
//  }
  @Override
  public Map<String, Object> getScheduleJobListByPage(Map<String, Object> param) {
    Map<String, Object> res = new HashMap<>();
    try {
      res = scheduleJobDao.getScheduleJobListByPage(param);
    } catch (Exception e) {
        log.error(e.toString());
    }

    return res;
  }

  @Override
  public Map<String, Object> getScheduleJobByParam(Map<String, Object> param) {
    Map<String, Object> res = new HashMap<>();
    return null;
  }

  @Override
  public Map<String, Object> insertScheduleJob(ScheduleJob ScheduleJob) {
    Map<String, Object> res = new HashMap<>();
    String msg = "";
    try {
      scheduleJobDao.insertScheduleJob(ScheduleJob);
      res.put("resCode", "0");
      res.put("resMsg", "添加数据成功");
    } catch (Exception e) {
      log.error("insertScheduleJob error ==> " + e);
      msg = e.toString();
      if (msg.length() > 200) {
        msg = msg.substring(0, 199);
      }
      res.put("resCode", "1");
      res.put("resMsg", msg);
    }
    return res;
  }

  @Override
  public Map<String, Object> updateScheduleJob(ScheduleJob scheduleJob) {

    Map<String, Object> res = new HashMap<>();
    String msg = "";
    if (scheduleJob.getId() == null || scheduleJob.getId() == 0){
      res.put("resCode", "0");
      res.put("resMsg", "ScheduleJob.id不能问空");
      return res;
    }
    try {
      scheduleJobDao.updateScheduleJob(scheduleJob);
      res.put("resCode", "0");
      res.put("resMsg", "编辑定时任务信息成功");
    } catch (Exception e) {
      log.error("updateScheduleJob error ==> " + e);
      msg = e.toString();
      if (msg.length() > 200) {
        msg = msg.substring(0, 199);
      }
      res.put("resCode", "1");
      res.put("resMsg", msg);
    }
    return res;
  }

  /**
   * 删除定时任务信息，先查出定时任务，然后从调度器里删除job，最后删除定时任务信息
   *
   * @param scheduleJob
   * @return
   */
  @Override
  public Map<String, Object> deleteScheduleJob(ScheduleJob scheduleJob) {
    Map<String, Object> res = new HashMap<>();
    String msg = "";
    if (scheduleJob.getId() == null || scheduleJob.getId() == 0){
      res.put("resCode", "0");
      res.put("resMsg", "ScheduleJob.id不能问空");
      return res;
    }
    try {
      ScheduleJob scheduleJobDel = scheduleJobDao.getScheduleJobById(scheduleJob);
      //删除调度器里job
      deleteJob(scheduleJobDel);
      //删除任务信息
      scheduleJobDao.deleteScheduleJob(scheduleJob);
      res.put("resCode", "0");
      res.put("resMsg", "删除定时任务信息成功");
    } catch (Exception e) {
      log.error("deleteScheduleJob error ==> " + e);
      msg = e.toString();
      if (msg.length() > 200) {
        msg = msg.substring(0, 199);
      }
      res.put("resCode", "1");
      res.put("resMsg", msg);
    }
    return res;
  }


  @Override
  public Map<String, Object> startJob(ScheduleJob job)  {

    Map<String, Object> res = new HashMap<>();
    res.put("resMsg", "启动成功");
    res.put("resCode", "0");
    try {
      //获取调度器
//      Scheduler scheduler = schedulerFactoryBean.getScheduler();
      // 获取trigger，即在spring配置文件中定义的 bean id="myTrigger" 创建cron触发器，指定组，除非器名字，使用规则
      TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
      CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
      if (null == trigger) {
        // 不存在，创建一个. 用JobDetail创建
        JobDetail jobDetail = JobBuilder.newJob(JobExchange.class)
            .withIdentity(job.getJobName(),job.getJobGroup())
            .usingJobData("jobName",job.getJobName())
            .usingJobData("serverUrl",job.getServerUrl())
            .usingJobData("sendMode",job.getSendMode())
            .build();

//        MethodInvokingJobDetailFactoryBean methodInvJobDetailFB = new MethodInvokingJobDetailFactoryBean();
//        methodInvJobDetailFB.setName(job.getJobName());
//        methodInvJobDetailFB
//            .setTargetObject((ScheduleTaskService) Class.forName(job.getClassName()).newInstance());
//        methodInvJobDetailFB.setTargetMethod(job.getMethod());
//        methodInvJobDetailFB.afterPropertiesSet();
//        methodInvJobDetailFB.setConcurrent(false);
//        JobDetail jobDetail = (JobDetail) methodInvJobDetailFB.getObject();// 动态
//        jobDetail.getJobDataMap().put("scheduleJob", job);
        // 表达式调度构建器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
            .cronSchedule(job.getCronExpression());
        // 按新的cronExpression表达式构建一个新的trigger
        trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup())
            .withSchedule(scheduleBuilder).build();
        // 加载定时任务
        scheduler.scheduleJob(jobDetail, trigger);
      } else {
        // Trigger已存在，那么更新相应的定时设置
        // 表达式调度构建器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
            .cronSchedule(job.getCronExpression());
        // 按新的cronExpression表达式重新构建trigger
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder)
            .build();
        // 按新的trigger重新设置job执行
        scheduler.rescheduleJob(triggerKey, trigger);
      }
      //启动成功后，修改状态为1，添加下次运行时间
      //state=1启用
      ScheduleJob scheduleJobUpdate = new ScheduleJob();
      CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
      try {
        cronTriggerImpl.setCronExpression(job.getCronExpression());
      } catch (Exception e) {
        log.warn("cronTriggerImpl.setCronExpression exception: " + e.toString());
      }
      List<Date> dateList = TriggerUtils.computeFireTimes(cronTriggerImpl, null, 1);
      if (dateList != null && dateList.size() > 0) {
        scheduleJobUpdate.setNextFireTime(
            DateUtil.getFormatTimeString(dateList.get(0), "yyyy-MM-dd HH:mm:ss"));
      }
      scheduleJobUpdate.setState("1");
      scheduleJobUpdate.setId(job.getId());
      updateScheduleJob(scheduleJobUpdate);
    } catch (Exception e) {
      String msg = e.toString();
      log.error(e.toString());
      if (msg.length() > 200) {
        msg = msg.substring(1, 199);
      }
      res.put("resCode", "1");
      res.put("resMsg", "启动失败:" + msg);
    }
    return res;
  }

  @Override
  public Map<String, Object> pauseJob(ScheduleJob job) {
    Map<String, Object> res = new HashMap<>();
    res.put("resMsg", "终止成功");
    res.put("resCode", "0");
    try {
      Scheduler scheduler = schedulerFactoryBean.getScheduler();
      JobKey jobKey = JobKey.jobKey(job.getJobName());
      scheduler.pauseJob(jobKey);
    } catch (SchedulerException e) {
      String msg = e.toString();
      log.error(e.toString());
      if (msg.length() > 200) {
        msg = msg.substring(1, 199);
      }
      res.put("resCode", "1");
      res.put("resMsg", "终止失败:" + msg);
    }
    return res;
  }

  @Override
  public ScheduleJob getScheduleJobById(ScheduleJob scheduleJob) {
    return this.scheduleJobDao.getScheduleJobById(scheduleJob);
  }
  /**
   *
   * 删除定时任务, 删除定时任务信息的时候使用
   */
  private void deleteJob(ScheduleJob job) throws Exception{
    Scheduler scheduler = schedulerFactoryBean.getScheduler();
    JobKey jobKey = JobKey.jobKey(job.getJobName());
    scheduler.deleteJob(jobKey);
  }



  @Override
  public void initJobs() {
    //查询所有定时任务
    Map<String, Object> getScheduleJobList = this.getScheduleJob();
    List<ScheduleJob> jobList = (List<ScheduleJob>) getScheduleJobList.get("scheduleJobList");
    for (ScheduleJob job : jobList) {
      //把设为启用状态的定时任务启动起来
      if ("1".equals(job.getState())) {
        try {
          Map res = startJob(job);
          if ("0".equals(res.get("resCode"))) {
            log.info("have start job");
          } else {
            //启动失败，把数据状态改为未启动0，记录原因
            ScheduleJob scheduleJobUpdate = new ScheduleJob();
            scheduleJobUpdate.setState("0");
            scheduleJobUpdate.setId(job.getId());
            String errorMsg = String.valueOf(res.get("resMsg"));
            if (errorMsg.length() > 79){
              errorMsg = errorMsg.substring(0,78);
            }
            scheduleJobUpdate.setRemark(errorMsg);
            log.error("job start fail,id: " + job.getId() + "==>" + res.get("resMsg"));
          }
        } catch (Exception e) {
          // 注意记录，启动失败原因
          log.error("job start fail,id: " + job.getId() + "==>" + e);
          //启动失败，把数据状态改为未启动0，记录原因
          ScheduleJob scheduleJobUpdate = new ScheduleJob();
          scheduleJobUpdate.setState("0");
          scheduleJobUpdate.setId(job.getId());
          String errorMsg = String.valueOf(e.toString());
          if (errorMsg.length() > 79){
            errorMsg = errorMsg.substring(0,78);
          }
          scheduleJobUpdate.setRemark(errorMsg);
        }
      }
    }
  }

  public Map<String, Objects> checkScheduleJob(ScheduleJob job){

    return new HashMap<>();
  }

}